package com.hy;

/**
 * Created With IntelliJ IDEA.
 * Descriptions:解数独
 *
 * 编写一个程序，通过填充空格来解决数独问题。
 * 数独的解法需 遵循如下规则：
 * 数字 1-9 在每一行只能出现一次。
 * 数字 1-9 在每一列只能出现一次。
 * 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。（请参考示例图）
 * 数独部分空格内已填入了数字，空白格用 '.' 表示。
 *
 * author: Mr.Du
 * Date: 2023/10/8
 * Time: 16:00
 */
public class SolveSudoku {

    int m = 9, n = 9;
    public void solveSudoku(char[][] board) {
        dfs(board, 0, 0);
    }

    /**
     * 返回类型是boolean，可以通过
     * @param board
     * @param r
     * @param c
     * @return
     */
    public boolean dfs(char[][] board, int r, int c){
        if(r == m){
            return true;
        }
        if(c == n){
            return dfs(board, r + 1, 0);
        }
        if(board[r][c] != '.'){
            return dfs(board, r, c + 1);
        }
        for (char ch = '1'; ch <= '9'; ch++) {
            // 如果遇到不合法的数字，就跳过
            if (!isValid(board, r, c, ch))
                continue;
            board[r][c] = ch;
            if(dfs(board, r, c + 1))
                return true;
            board[r][c] = '.';
        }
        return false;
    }

    /**
     * 返回值类型为void，不能通过，思路都是一样的，不知道为什么
     * @param board
     * @param r
     * @param c
     */
    public void dfsWithVoid(char[][] board, int r, int c){
        if(r == m){
            return;
        }
        if(c == n){
            dfs(board, r + 1, 0);
            return;
        }
        if(board[r][c] != '.'){
            dfs(board, r, c + 1);
            return;
        }
        for (char ch = '1'; ch <= '9'; ch++) {
            // 如果遇到不合法的数字，就跳过
            if (!isValid(board, r, c, ch))
                continue;
            board[r][c] = ch;
            dfsWithVoid(board, r, c + 1);
            board[r][c] = '.';
        }
    }

    public boolean isValid(char[][] board, int r, int c, char ch){
        for (int i = 0; i < 9; i++) {
            // 判断行是否存在重复
            if (board[r][i] == ch) return false;
            // 判断列是否存在重复
            if (board[i][c] == ch) return false;
            // 判断 3 x 3 方框是否存在重复
            if (board[(r/3)*3 + i/3][(c/3)*3 + i%3] == ch)
                return false;
        }
        return true;
    }
}
